package com.cloudkinto.utils;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Redis操作hash表的工具类
 *
 * @author long
 */
@Component
@RequiredArgsConstructor
public class RedisHashUtil {
    private final RedisTemplate redisTemplate;

    /**
     * 在原有hash基础上，为key中field字段加上逻辑过期时间（需要在查询时过滤删除）
     *
     * @param hashKey    哈希表键值
     * @param field      字段
     * @param value      值
     * @param expireTime 过期时间
     * @param timeUnit   时间单位
     */
    public void setHashValue(String hashKey, String field, String value, Long expireTime, TimeUnit timeUnit) {
        //将field拼接一个时间串，根据TimeUnit和当前时间计算
        //断言expireTime不为空
        assert expireTime != null : "expireTime can not be null";
        if (!expireTime.equals(0L)) {
            LocalDateTime localDateTime = LocalDateTime.now();
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            switch (timeUnit) {
                case DAYS:
                    localDateTime = expireTime > 0 ? localDateTime.plusDays(expireTime) : localDateTime.minusDays(expireTime);
                    break;
                case HOURS:
                    localDateTime = expireTime > 0 ? localDateTime.plusHours(expireTime) : localDateTime.minusHours(expireTime);
                    break;
                case MINUTES:
                    localDateTime = expireTime > 0 ? localDateTime.plusMinutes(expireTime) : localDateTime.minusMinutes(expireTime);
                    break;
                case SECONDS:
                    localDateTime = expireTime > 0 ? localDateTime.plusSeconds(expireTime) : localDateTime.minusSeconds(expireTime);
                    break;
                case MILLISECONDS:
                    localDateTime = expireTime > 0 ? localDateTime.plusSeconds(expireTime / 1000) : localDateTime.minusSeconds(expireTime / 1000);
                    break;
                case MICROSECONDS:
                    localDateTime = expireTime > 0 ? localDateTime.plusSeconds(expireTime / 1000000) : localDateTime.minusSeconds(expireTime / 1000000);
                    break;
                case NANOSECONDS:
                    localDateTime = expireTime > 0 ? localDateTime.plusNanos(expireTime) : localDateTime.minusNanos(expireTime);
                    break;
                default:
                    break;
            }
            //将localDateTime转换为我们想要的日期字符串
            String expireTimeStr = dateTimeFormatter.format(localDateTime);
            redisTemplate.opsForHash().put(hashKey, field + "," + expireTimeStr, value);
            return;
        }
        //如果expireTime等于0，走默认逻辑
        redisTemplate.opsForHash().put(hashKey, field, value);
    }

    /**
     * 获取hash表中有效的值
     *
     * @param hashKey 哈希表键值
     * @return 值
     */
    public Map<String, Object> getValidHashValue(String hashKey) {
        Map<String, Object> res = new HashMap<>();
        Map<String, Object> map = redisTemplate.opsForHash().entries(hashKey);
        //过滤map中逗号分隔的时间小于现在时间的key
        map.forEach((key, value) -> {
            if (key.contains(",")) {
                LocalDateTime expireTime = LocalDateTime.parse(key.split(",")[1], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                if (expireTime.isAfter(LocalDateTime.now())) {
                    res.put(key.split(",")[0], value);
                }
            } else {
                res.put(key, value);
            }
        });

        return res;
    }

    /**
     * 清理hash表中某个key的field字段
     *
     * @param hashKey 哈希表键值
     */
    public void clearHashField(String hashKey) {
        HashSet<String> fields = new HashSet<>();
        //获取已过期的field
        Map<String, Object> map = redisTemplate.opsForHash().entries(hashKey);
        //获取已过期的field
        map.forEach((key, value) -> {
            if (key.contains(",")) {
                LocalDateTime expireTime = LocalDateTime.parse(key.split(",")[1], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                if (expireTime.isBefore(LocalDateTime.now())) {
                    fields.add(key);
                }
            }
        });
        //批量删除hash表中的key
        Object[] fieldArray = fields.toArray();
        if (fieldArray.length > 0) {
            redisTemplate.opsForHash().delete(hashKey, fieldArray);
        }
    }

}
